#pragma once

#include <G3D/Matrix3.h>
#include <G3D/Vector3.h>
#include <G3D/AABox.h>
#include <G3D/Ray.h>


namespace vmap
{
    class WorldModel;
    struct AreaInfo;
    struct LocationInfo;

    /**
     * @brief
     *
     */
    enum ModelFlags
    {
        MOD_M2 = 1,
        MOD_WORLDSPAWN = 1 << 1,
        MOD_HAS_BOUND = 1 << 2
    };

    /**
     * @brief
     *
     */
    class ModelSpawn
    {
    public:
        // mapID, tileX, tileY, Flags, ID, Pos, Rot, Scale, Bound_lo, Bound_hi, name
        unsigned int flags; /**< TODO */
        unsigned short adtId; /**< TODO */
        unsigned int ID; /**< TODO */
        G3D::Vector3 iPos; /**< TODO */
        G3D::Vector3 iRot; /**< TODO */
        float iScale; /**< TODO */
        G3D::AABox iBound; /**< TODO */
        std::string name; /**< TODO */
        /**
         * @brief
         *
         * @param other
         * @return bool operator
         */
        bool operator==(const ModelSpawn& other) const { return ID == other.ID; }
        // unsigned int hashCode() const { return ID; }
        // temp?
        /**
         * @brief
         *
         * @return const G3D::AABox
         */
        const G3D::AABox& getBounds() const { return iBound; }


        /**
         * @brief
         *
         * @param rf
         * @param spawn
         * @return bool
         */
        static bool ReadFromFile(FILE* rf, ModelSpawn& spawn);
        /**
         * @brief
         *
         * @param rw
         * @param spawn
         * @return bool
         */
        static bool WriteToFile(FILE* rw, const ModelSpawn& spawn);
    };

    /**
     * @brief
     *
     */
    class ModelInstance : public ModelSpawn
    {
    public:
        /**
         * @brief
         *
         */
        ModelInstance() : iModel(0) {}
        /**
         * @brief
         *
         * @param spawn
         * @param model
         */
        ModelInstance(const ModelSpawn& spawn, WorldModel* model);
        /**
         * @brief
         *
         */
        void setUnloaded() { iModel = 0; }
        /**
         * @brief
         *
         * @param pRay
         * @param pMaxDist
         * @param pStopAtFirstHit
         * @return bool
         */
        bool intersectRay(const G3D::Ray& pRay, float& pMaxDist, bool pStopAtFirstHit) const;
        /**
         * @brief
         *
         * @param p
         * @param info
         */
        void GetAreaInfo(const G3D::Vector3& p, AreaInfo& info) const;
        /**
         * @brief
         *
         * @param p
         * @param info
         * @return bool
         */
        bool GetLocationInfo(const G3D::Vector3& p, LocationInfo& info) const;
        /**
         * @brief
         *
         * @param p
         * @param info
         * @param liqHeight
         * @return bool
         */
        bool GetLiquidLevel(const G3D::Vector3& p, LocationInfo& info, float& liqHeight) const;
    protected:
        G3D::Matrix3 iInvRot; /**< TODO */
        float iInvScale; /**< TODO */
        WorldModel* iModel; /**< TODO */

#ifdef MMAP_GENERATOR
    public:
        WorldModel* const getWorldModel();
#endif
    };
}

